package pl.ydp.components.mathcell.mathrecognizer.geometry.extractor.features
{
	import flash.geom.Point;
	
	import pl.ydp.components.mathcell.mathrecognizer.engine.Parameters;
	import pl.ydp.components.mathcell.mathrecognizer.structures.Span;
	
	public class FeaturesLoop
	{
		
		
		public static function findLoopClosure(vectors:Array, begin:Number, end:Number):Span{
			
			var v:Number;
			var testBegin:Number
			var testEnd:Number;
			
			var currBeginIndex:Number;
			var currEndIndex:Number;
			
			var beginOptized:Boolean;
			var endOptized:Boolean;
			
			var finalBegin:Number;
			var finalEnd:Number;
			
			var minDistance:Number;
			var currDistance:Number;
			
			const CRAWL_RANGE:Number = 4;
			const CRAWL_MAX_STEPS:Number = 4;
			
			currBeginIndex = begin;
			currEndIndex = end;
			
			for (v = 0 ; v < CRAWL_MAX_STEPS ; v += CRAWL_RANGE ){
								
				beginOptized = false;
				endOptized = false;
				
				minDistance = Point.distance(vectors[currBeginIndex].point, vectors[currEndIndex].point);
				
				if (currEndIndex - currBeginIndex < Parameters.LOOP_MIN_LENGTH+CRAWL_RANGE){
					break;
				}

				for (testBegin = currBeginIndex - CRAWL_RANGE/2 ; testBegin < currBeginIndex + CRAWL_RANGE/2 ; testBegin ++ ){
					
					if (testBegin < 0){
						continue;
					}
					
					for (testEnd = currEndIndex - CRAWL_RANGE/2 ; testEnd < currEndIndex + CRAWL_RANGE/2 ; testEnd ++ ){
						
						if (testEnd >= vectors.length){
							continue;
						}
						
						currDistance = Point.distance(vectors[testBegin].point, vectors[testEnd].point);
						
						if (currDistance < minDistance){
							minDistance = currDistance;
							
							if (currBeginIndex != testBegin){
								currBeginIndex = testBegin;
								beginOptized = true;
							}
							if (currEndIndex != testEnd){
								currEndIndex = testEnd;
								endOptized = true;
							}
							
						}
						
					}	
				}
			
				if (!beginOptized  &&  !endOptized){
					break;
				}
				
				
			} // end for (v...
			
			
			return new Span(currBeginIndex, currEndIndex);
		}
		
		//------------------------------------------------------------------
		
		public static function findDiameter(vectors:Array, beginIndex:Number = 0):LoopDiameter{
			
			var v:Number;
			var distance:Number;
			
			var maxDiameter:Number = 0;
			var maxDiameterSatelliteIndex:Number;
			
			for (v = 0 ; v < vectors.length ; v ++ ){
				
				distance = Point.distance(vectors[beginIndex].point, vectors[v].point); 
				
				if (distance > maxDiameter){
					maxDiameter = distance;
					maxDiameterSatelliteIndex = v;
				}
			}
			
			return new LoopDiameter(vectors[beginIndex].point, vectors[maxDiameterSatelliteIndex].point);
				
		}
		
		//------------------------------------------------------------------
		
		public static function findDiameterSecond2V(vectors0:Array, vectors1:Array, center:Point):LoopDiameter{
			
			var test2:Number;
			
			var tmpDist:Number;	
			var min0:Number = Infinity; 
			var min1:Number = Infinity;
			
			var min0Index:Number;
			var min1Index:Number;
																						
			for (test2 = 0 ; test2 < vectors0.length ; test2 ++ ) {
				tmpDist = Point.distance(center, vectors0[test2].point);
				if (tmpDist < min0){
					min0 = tmpDist;
					min0Index = test2;
				}
			}
			
			for (test2 = 0 ; test2 < vectors1.length ; test2 ++ ) {
				tmpDist = Point.distance(center, vectors1[test2].point);
				if (tmpDist < min1){
					min1 = tmpDist;
					min1Index = test2;
				}
			}
			
			return new LoopDiameter(vectors0[min0Index].point, vectors1[min1Index].point);		
			
		}
		
		//------------------------------------------------------------------
		
		public static function findDiameterSecond(vectors:Array, begin:Number, end:Number, satellite:Number, center:Point):LoopDiameter{
			
			var test2:Number;
			
			var tmpDist:Number;	
			var min0:Number = Infinity; 
			var min1:Number = Infinity;
			
			var min0Index:Number;
			var min1Index:Number;
																						
			for (test2 = begin+1 ; test2 < satellite ; test2 ++ ) {
				tmpDist = Point.distance(center, vectors[test2].point);
				if (tmpDist < min0){
					min0 = tmpDist;
					min0Index = test2;
				}
			}
			if (begin+1 >= satellite){
				min0Index = satellite;
			}
			
			for (test2 = satellite ; test2 < end ; test2 ++ ) {
				tmpDist = Point.distance(center, vectors[test2].point);
				if (tmpDist < min1){
					min1 = tmpDist;
					min1Index = test2;
				}
			}
			if (satellite >= end){
				min1Index = satellite;
			}
			
			return new LoopDiameter(vectors[min0Index].point, vectors[min1Index].point);
		}
		
		//------------------------------------------------------------------
		
	}
}